#include "bhxjglmodel.h"

BHXJGLMesh::BHXJGLMesh()
{

}
BHXJGLMesh::~BHXJGLMesh()
{
    if(gl!=nullptr)
    {
        //gl->glDeleteBuffers(1,&VBO);
        //gl->glDeleteBuffers(1,&EBO);
        //以上两行有效会产生莫名错误，清理VAO后则不用清理EBO和VBO？可能和qt opengl上下文处理方式有关?
        gl->glDeleteVertexArrays(1,&VAO);
        gl->glInvalidateBufferData(EBO);
        gl->glInvalidateBufferData(VBO);
    }
}
void BHXJGLMesh::Init(BHXJGLFUN *glcore)
{
    this->gl=glcore;
    gl->glGenVertexArrays(1, &VAO);
    gl->glGenBuffers(1, &VBO);
    gl->glGenBuffers(1, &EBO);

    gl->glBindVertexArray(VAO);
    gl->glBindBuffer(GL_ARRAY_BUFFER, VBO);

    gl->glBufferData(GL_ARRAY_BUFFER, static_cast<int>(vertices.size() * sizeof(BHXJGLVertex)) , &vertices[0], GL_STATIC_DRAW);

    gl->glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
    gl->glBufferData(GL_ELEMENT_ARRAY_BUFFER, static_cast<int>(indices.size() * sizeof(unsigned int)),
                     &indices[0], GL_STATIC_DRAW);

    // 顶点位置
    gl->glEnableVertexAttribArray(0);
    gl->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(BHXJGLVertex), reinterpret_cast<void *>(offsetof(BHXJGLVertex, position)));
    // 顶点法线
    gl->glEnableVertexAttribArray(1);
    gl->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(BHXJGLVertex), reinterpret_cast<void *>(offsetof(BHXJGLVertex, normal)));
    // 顶点纹理坐标
    gl->glEnableVertexAttribArray(2);
    gl->glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(BHXJGLVertex), reinterpret_cast<void *>(offsetof(BHXJGLVertex, texcoodr)));
    gl->glBindVertexArray(0);

    std::vector<BHXJGLVertex>().swap(vertices);
    std::vector<unsigned int>().swap(indices);
}


void BHXJGLMesh::Paint(BHXJGLShader *ishader)
{
    ishader->use();
    for(unsigned int i=0;i<textures.size();++i)
    {
        textures.at(i)->Use(i);
    }

    this->gl->glBindVertexArray(VAO);
    this->gl->glDrawElements(GL_TRIANGLES,static_cast<int>(trianglescount*3),GL_UNSIGNED_INT,nullptr);
    this->gl->glBindVertexArray(0);
}





BHXJGLTexture2D::BHXJGLTexture2D()
{

}
BHXJGLTexture2D::~BHXJGLTexture2D()
{
    if(this->gl!=nullptr&&this->textID!=0)
    {
        gl->glInvalidateTexImage(textID,0);
    }
}
void BHXJGLTexture2D::Init(BHXJGLFUN *glcore, const std::string &Path)
{
    gl=glcore;
    int width, height, nrChannels;
    stbi_set_flip_vertically_on_load(true);
    unsigned char *data =stbi_load(Path.c_str(), &width, &height, &nrChannels, 4);
    gl->glGenTextures(1, &textID);
    gl->glBindTexture(GL_TEXTURE_2D, textID);
    gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
    gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
    gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    gl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    gl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
    gl->glGenerateMipmap(GL_TEXTURE_2D);
    stbi_image_free(data);
}
void BHXJGLTexture2D::Use(unsigned int index)
{
    if(this->gl!=nullptr&&this->textID!=0)
    {
        gl->glActiveTexture(GL_TEXTURE0+index);
        gl->glBindTexture(GL_TEXTURE_2D, textID);
    }
}




BHXJGLPaintParam::BHXJGLPaintParam()
{

}
BHXJGLPaintParam::~BHXJGLPaintParam()
{

}
const glm::mat4& BHXJGLPaintParam::Model()const
{
    return _Model;
}
void BHXJGLPaintParam::setModel()
{
    _Model[0]=glm::vec4(glm::normalize(_Right),0);
    _Model[1]=glm::vec4(glm::normalize(_Up),0);
    _Model[2]=glm::vec4(glm::normalize(glm::cross(_Right,_Up)),0);
    _Model[3]=glm::vec4(_Position,1);
    _Model=glm::scale(_Model,_Size);

}


//template<class... Args>
//BHXJGLModel<Args...>::BHXJGLModel()
//{

//}

//template<class... Args>
//BHXJGLModel<Args...>::~BHXJGLModel()
//{
//    for(BHXJGLMesh *m: meshes)
//    {
//        delete m;
//    }
//    for(BHXJGLTexture2D *t: textures)
//    {
//        delete t;
//    }
//}

//template<class... Args>
//void BHXJGLModel<Args...>::Paint(const BHXJGLPaintParam &p)
//{
//    BHXJGLShader* shader;
//    if(shaders.size()>0)
//    {
//        shader=shaders[0];
//        shader->use();
//        shader->setMat4("projection",p.Projection());
//        shader->setMat4("view",p.View());
//        shader->setMat4("model",p.Model());
//    }
//    if(shader==nullptr)
//        return;
//    for(BHXJGLMesh *bh:meshes)
//    {
//        bh->Paint(shader);
//    }
//}

//template<class... Args>
//void BHXJGLModel<Args...>::Paint(const BHXJGLPaintParam &p,BHXJGLShader *ishader)
//{
//    BHXJGLShader *shader=nullptr;
//    if(ishader!=nullptr)
//        shader=ishader;
//    else
//    {
//        if(shaders.size()>0)
//        {
//            shader=shaders[0];
//        }
//    }
//    if(shader==nullptr)
//        return;

//    shader->use();
//    shader->setMat4("projection",p.Projection());
//    shader->setMat4("view",p.View());
//    shader->setMat4("model",p.Model());
//    for(BHXJGLMesh *bh:meshes)
//    {
//        bh->Paint(shader);
//    }
//}

//template<class... Args>
//void BHXJGLModel<Args...>::Paint(const glm::mat4 &projection,const glm::mat4 &view,const glm::mat4 &model,BHXJGLShader *ishader)
//{
//    BHXJGLShader *shader=nullptr;
//    if(ishader!=nullptr)
//        shader=ishader;
//    else
//    {
//        if(shaders.size()>0)
//        {
//            shader=shaders[0];
//        }
//    }
//    if(shader==nullptr)
//        return;

//    shader->use();
//    shader->setMat4("projection",projection);
//    shader->setMat4("view",view);
//    shader->setMat4("model",model);
//    for(BHXJGLMesh *bh:meshes)
//    {
//        bh->Paint(shader);
//    }
//}

